/*******************************************************************************
 *                                    ZLG
 *                         ----------------------------
 *                         innovating embedded platform
 *
 * Copyright (c) 2001-present Guangzhou ZHIYUAN Electronics Co., Ltd.
 * All rights reserved.
 *
 * Contact information:
 * web site:    https://www.zlg.cn
 *******************************************************************************/
#ifndef __ARMV7M_CORE_H__
#define __ARMV7M_CORE_H__

#include <stdio.h>
#include "common/hc32f4a0_common.h"

/* \brief 系统控制空间基地址*/
#define ARMV7M_SCS_BASE         (0xE000E000UL)
/* \brief 系统控制块基地址*/
#define ARMV7M_SCB_BASE         (ARMV7M_SCS_BASE +  0x0D00UL)
/* \brief SysTick 基地址*/
#define ARMV7M_SYSTICK_BASE     (ARMV7M_SCS_BASE +  0x0010UL)
/* \brief 嵌套向量中断控制寄存器基地址 */
#define ARMV7M_NVIC_BASE        (ARMV7M_SCS_BASE +  0x0100UL)

/* \brief 系统控制块结构 */
typedef struct {
    volatile uint32_t CPUID;            /* CPU ID 基本寄存器，偏移: 0x000 (R/ ) */
    volatile uint32_t ICSR;             /* 中断控制和状态寄存器，偏移: 0x004 (R/W) */
    volatile uint32_t VTOR;             /* 向量表偏移寄存器，偏移: 0x008 (R/W) */
    volatile uint32_t AIRCR;            /* 应用中断及复位控制寄存器，偏移: 0x00C (R/W) */
    volatile uint32_t SCR;              /* 系统控制寄存器，偏移: 0x010 (R/W) */
    volatile uint32_t CCR;              /* 配置控制寄存器，偏移: 0x014 (R/W) */
    volatile uint8_t  SHP[12];          /* 系统处理优先级寄存器(4-7, 8-11, 12-15)，偏移:0x018 (R/W) */
    volatile uint32_t SHCSR;            /* 系统处理控制和状态寄存器，偏移: 0x024 (R/W) */
    volatile uint32_t CFSR;             /* 皮质错误状态寄存器，偏移: 0x028 (R/W) */
    volatile uint32_t HFSR;             /* 硬件错误状态寄存器，偏移: 0x02C (R/W) */
    volatile uint32_t DFSR;             /* 调试错误状态寄存器，偏移: 0x030 (R/W) */
    volatile uint32_t MMFAR;            /* 内存管理错误地址寄存器，偏移: 0x034 (R/W) */
    volatile uint32_t BFAR;             /* 总线错误地址寄存器，偏移: 0x038 (R/W) */
    volatile uint32_t AFSR;             /* 辅助错误状态寄存器，偏移: 0x03C (R/W) */
    volatile uint32_t PFR[2];           /* 处理器特性寄存器，偏移: 0x040 (R/ ) */
    volatile uint32_t DFR;              /* 调试特性寄存器，偏移: 0x048 (R/ ) */
    volatile uint32_t ADR;              /* 辅助特性寄存器，偏移: 0x04C (R/ ) */
    volatile uint32_t MMFR[4];          /* 内存模型特性寄存器，偏移: 0x050 (R/ ) */
    volatile uint32_t ISAR[5];          /* 指令集属性寄存器，偏移: 0x060 (R/ ) */
    volatile uint32_t RESERVED0[5];
    volatile uint32_t CPACR;            /* 协处理器访问控制寄存器 ，偏移: 0x088 (R/W) */
} armv7m_scb_t;

/* \brief SysTick 加载寄存器定义 */
#define SysTick_LOAD_RELOAD_Pos             0U             /* 重载位置*/
#define SysTick_LOAD_RELOAD_Msk            (0xFFFFFFUL)    /* 重载掩码 */

/* \brief SysTick 控制寄存器定义 */
#define SYSTICK_CTRL_CLKSOURCE_POS         (2U)                              /* SysTick 时钟源选择位置 */
#define SYSTICK_CTRL_CLKSOURCE_MASK        (1 << SYSTICK_CTRL_CLKSOURCE_POS) /* SysTick 时钟源选择掩码*/
#define SYSTICK_CTRL_TICKINT_POS           (1U)                              /* SysTick 异常请求使能位置*/
#define SYSTICK_CTRL_TICKINT_MASK          (1 << SYSTICK_CTRL_TICKINT_POS)   /* SysTick 异常请求使能掩码*/
#define SYSTICK_CTRL_ENABLE_POS            (0U)                              /* SysTick 使能计数器位置*/
#define SYSTICK_CTRL_ENABLE_MASK           (1 << SYSTICK_CTRL_ENABLE_POS)    /* SysTick 使能计数器掩码*/

/* \brief SysTick 结构体定义*/
typedef struct {
    volatile        uint32_t CTRL;       /* SysTick控制与状态寄存器，偏移:0x000 (R/W) */
    volatile        uint32_t LOAD;       /* SysTick加载值寄存器，偏移:0x004 (R/W) */
    volatile        uint32_t VAL;        /* SysTick当前值寄存器，偏移:0x008 (R/W) */
    volatile const  uint32_t CALIB;      /* SysTick校准寄存器，偏移:0x00C (R/ ) */
} armv7m_systick_t;

/* \brief 嵌套向量中断控制结构体定义*/
typedef struct {
    volatile uint32_t ISER[8U];          /* 中断设置使能寄存器，偏移:0x000 (R/W) */
    uint32_t          RESERVED0[24U];
    volatile uint32_t ICER[8U];          /* 中断清除使能寄存器，偏移:0x080 (R/W) */
    uint32_t          RSERVED1[24U];
    volatile uint32_t ISPR[8U];          /* 中断设置挂起寄存器，偏移:0x100 (R/W) */
    uint32_t          RESERVED2[24U];
    volatile uint32_t ICPR[8U];          /* 中断清除挂起寄存器，偏移:0x180 (R/W) */
    uint32_t          RESERVED3[24U];
    volatile uint32_t IABR[8U];          /* 中断激活位寄存器，偏移:0x200 (R/W) */
    uint32_t          RESERVED4[56U];
    volatile uint8_t  IP[240U];          /* 中断优先级寄存器(8位宽)，偏移:0x300 (R/W) */
    uint32_t          RESERVED5[644U];
    volatile uint32_t STIR;              /* 软件触发中断寄存器，偏移:0xE00 ( /W) */
}  armv7m_nvic_t;

/* \brief 中断优先级位数*/
#define __NVIC_PRIO_BITS              4U

/* \brief NVIC 处理函数*/
#define NVIC_SetPriority            __NVIC_SetPriority
#define NVIC_EnableIRQ              __NVIC_EnableIRQ
#define NVIC_DisableIRQ             __NVIC_DisableIRQ
#define NVIC_ClearPendingIRQ        __NVIC_ClearPendingIRQ

typedef struct {
    uint32_t          RESERVED0[1];
    volatile uint32_t ICTR;              /* 中断控制类型寄存器 */
    volatile uint32_t ACTLR;             /* 辅助控制寄存器 */
} armv7m_scn_scb_t;

#define ARMV7M_SCB      ((armv7m_scb_t *)ARMV7M_SCB_BASE)
#define ARMV7M_SYSTICK  ((armv7m_systick_t *)ARMV7M_SYSTICK_BASE)
#define ARMV7M_NVIC     ((armv7m_nvic_t *)ARMV7M_NVIC_BASE)
#define ARMV7M_SCnSCB   ((armv7m_scn_scb_t *)ARMV7M_SCS_BASE)

/**
 * \brief 设置中断优先级函数
 */
static inline void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t Priority){
    if ((int32_t)(IRQn) >= 0) {
        /* 普通中断优先级设置*/
        ARMV7M_NVIC->IP[((uint32_t)IRQn)]               = (uint8_t)((Priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
    } else {
        /* 内核级异常优先级设置*/
        ARMV7M_SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((Priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
    }
}

/**
 * \brief 清除挂起中断
 */
static inline void __NVIC_ClearPendingIRQ(IRQn_Type IRQn){
    if ((int32_t)(IRQn) >= 0) {
        ARMV7M_NVIC->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));
    }
}

/**
 * \brief 使能中断
 */
static inline void __NVIC_EnableIRQ(IRQn_Type IRQn){
    if ((int32_t)(IRQn) >= 0) {
        ARMV7M_NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));
    }
}

/**
 * \brief 关闭中断
 */
static inline  void __NVIC_DisableIRQ(IRQn_Type IRQn){
    if ((int32_t)(IRQn) >= 0) {
        ARMV7M_NVIC->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL));
        __asm volatile ("dsb 0xF":::"memory");
        __asm volatile ("isb 0xF":::"memory");
    }
}

/**
 * \brief 获取当前中断号
 */
static inline int __NVIC_IRQ_NumGet(void){
    return (int)((ARMV7M_SCB->ICSR - 16) & 0xff);
}

/**
 * \brief systick 配置函数
 */
static inline uint32_t systick_config(uint32_t Ticks) {
    /* 检查需要重载的值是否超过范围*/
    if ((Ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) {
        return (1UL);
    }
    /* 设置重载寄存器 */
    ARMV7M_SYSTICK->LOAD  = (uint32_t)(Ticks - 1UL);
    /* 设置 SysTick 中断优先级 */
    NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL);
    /* 加载 SysTick 计数器值*/
    ARMV7M_SYSTICK->VAL   = 0UL;
    /* 使能 SysTick 中断和 SysTick 定时器 */
    ARMV7M_SYSTICK->CTRL  = SYSTICK_CTRL_CLKSOURCE_MASK |
                            SYSTICK_CTRL_TICKINT_MASK   |
                            SYSTICK_CTRL_ENABLE_MASK;
    return (0UL);
}

#endif
